package com.landinfo.web.rest;

import com.codahale.metrics.annotation.Timed;
import com.github.junrar.Archive;
import com.github.junrar.exception.RarException;
import com.github.junrar.exception.RarException.RarExceptionType;
import com.github.junrar.rarfile.FileHeader;
import com.landinfo.service.ShapefileService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;

import java.io.*;
import java.net.URISyntaxException;
import java.nio.charset.Charset;
import java.util.Enumeration;
import java.util.List;
import java.util.UUID;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;

/**
 * Created by ziqilv on 2017/4/6.
 * Shapefile文件管理
 */
@RestController
@RequestMapping("/api")
public class ShapeFileResource {
  private final Logger log = LoggerFactory.getLogger(ShapeFileResource.class);

  private static final String ENTITY_NAME = "shp";
  private final ShapefileService shapefileService;

  public ShapeFileResource(ShapefileService shapefileService) {
    this.shapefileService = shapefileService;
  }

  /**
   * 获取应用程序路径
   *
   * @return
   */
  private String getApplicationPath() {
    String path = this.getClass().getResource("/").getPath();
    try {
      path = java.net.URLDecoder.decode(path, "utf-8");
    } catch (UnsupportedEncodingException e) {
      e.printStackTrace();
    }
    File file2 = new File(path);
    file2 = new File(file2.getParent());
    path = file2.getParent() +File.separator+ "shp"+File.separator;
    return path;
  }

  /**
   * 文件上传具体实现方法;
   *
   * @param file
   * @return
   */
  @PostMapping("/shp/upload")
  @Timed
  public ResponseEntity shapeFileUpload(@RequestParam MultipartFile file) {
    log.debug("upload start");
    if (!file.isEmpty()) {
      try {
        String oldFileName = file.getOriginalFilename();
        String newFileName = UUID.randomUUID().toString() + oldFileName.substring(oldFileName.lastIndexOf("."));
        String path = this.getApplicationPath();
        File tempFile = new File(path);
        if (!tempFile.exists()) {
          tempFile.mkdirs();
        }
        File newFile = new File(path + newFileName);
        BufferedOutputStream out = new BufferedOutputStream(new FileOutputStream(newFile));
        out.write(file.getBytes());
        out.flush();
        out.close();
        String newShpPath = newFile.getAbsolutePath().substring(0, newFile.getAbsolutePath().length() - 4);
        String newShpFileName = unzip(newFile.getAbsolutePath());
        String newShp = newShpPath + File.separator + newShpFileName.substring(0, newShpFileName.indexOf('.')) + ".shp";
        String result = shapefileService.openShpFile(newShp);
        return new ResponseEntity<>(result, HttpStatus.OK);
      } catch (FileNotFoundException e) {
        e.printStackTrace();
        return new ResponseEntity<>("上传失败," + e.getMessage(), HttpStatus.OK);
      } catch (IOException e) {
        e.printStackTrace();
        return new ResponseEntity<>("上传失败," + e.getMessage(), HttpStatus.OK);
      } catch (URISyntaxException e) {
        e.printStackTrace();
        return new ResponseEntity<>("上传失败," + e.getMessage(), HttpStatus.OK);
      }
    } else {
      return new ResponseEntity<>("上传失败，因为文件是空的.", HttpStatus.OK);
    }
  }

  /**
   * 第一个参数是压缩文件路径，第二个参数是要解压的文件夹路径，文件夹可以不存在会自动生成
   */
  public String unzip(String file) throws IOException {
    String result = "";
    File fSourceZip = new File(file);
    String zipPath = file.substring(0, file.length() - 4);
    File temp = new File(zipPath);
    temp.mkdir();
    ZipFile zipFile = new ZipFile(fSourceZip, Charset.forName("gbk"));
    Enumeration en = zipFile.entries();  //.getEntries();
    while (en.hasMoreElements()) {
      ZipEntry entry = (ZipEntry) en.nextElement();
      String newFileName = entry.getName();
      if (newFileName.lastIndexOf('/') >= 0) {
        newFileName = newFileName.substring(newFileName.lastIndexOf('/') + 1);
      }
      File destinationFilePath = new File(zipPath, newFileName);
//      destinationFilePath.getParentFile().mkdirs();
      if (entry.isDirectory()) {
        continue;
      } else {
        result = newFileName;
        BufferedInputStream bis = new BufferedInputStream(zipFile.getInputStream(entry));

        int b;
        byte buffer[] = new byte[1024];

        FileOutputStream fos = new FileOutputStream(destinationFilePath);
        BufferedOutputStream bos = new BufferedOutputStream(fos, 1024);

        while ((b = bis.read(buffer, 0, 1024)) != -1) {
          bos.write(buffer, 0, b);
        }

        bos.flush();
        bos.close();
        bis.close();
      }
      if (entry.getName().endsWith(".zip")) {
        unzip(destinationFilePath.getAbsolutePath());
      }
    }
    return result;
  }

  /**
   * @param rarFileName rar file name
   * @param outFilePath output file path
   * @return success Or Failed
   * @throws Exception
   * @author zhuss
   */
  public static boolean unrar(String rarFileName, String outFilePath) throws Exception {

    boolean flag = false;
    try {
      Archive archive = new Archive(new File(rarFileName));
      if (archive == null) {
        throw new FileNotFoundException(rarFileName + " NOT FOUND!");
      }
      if (archive.isEncrypted()) {
        throw new Exception(rarFileName + " IS ENCRYPTED!");
      }
      List<FileHeader> files = archive.getFileHeaders();
      for (FileHeader fh : files) {
        if (fh.isEncrypted()) {
          throw new Exception(rarFileName + " IS ENCRYPTED!");
        }
        String fileName = fh.getFileNameW();
        if (fileName != null && fileName.trim().length() > 0) {
          String saveFileName = outFilePath + File.separator + fileName;
          File saveFile = new File(saveFileName);
          File parent = saveFile.getParentFile();
          if (!parent.exists()) {
            parent.mkdirs();
          }
          if (!saveFile.exists()) {
            saveFile.createNewFile();
          }
          FileOutputStream fos = new FileOutputStream(saveFile);
          try {
            archive.extractFile(fh, fos);
            fos.flush();
            fos.close();
          } catch (RarException e) {
            if (e.getType().equals(RarExceptionType.notImplementedYet)) {
            }
          } finally {
          }
        }
      }
      flag = true;
    } catch (Exception e) {
      e.printStackTrace();
      throw e;
    }
    return flag;
  }
}
